package com.jyw.business.obstacles.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jyw.business.obstacles.constant.OrderCurrStateConstant;
import com.jyw.business.obstacles.constant.OrderExamineStateConstant;
import com.jyw.business.obstacles.constant.OrderProcessStateConstant;
import com.jyw.business.obstacles.constant.OrderSourceConstant;
import com.jyw.business.obstacles.domain.ObsOrderFault;
import com.jyw.business.obstacles.domain.ObsOrderInfo;
import com.jyw.business.obstacles.domain.ObsOrderProcess;
import com.jyw.business.obstacles.domain.ObsOrderSend;
import com.jyw.business.obstacles.domain.dto.web.*;
import com.jyw.business.obstacles.domain.dto.wechat.WorkOrderQueryDto;
import com.jyw.business.obstacles.domain.dto.wechat.WxWorkOrderQueryPageDto;
import com.jyw.business.obstacles.domain.dto.wechat.WxWorkOrderReviewPageDto;
import com.jyw.business.obstacles.domain.vo.web.*;
import com.jyw.business.obstacles.domain.vo.wechat.WorkOrderQueryVO;
import com.jyw.business.obstacles.domain.vo.wechat.WxWorkOrderQueryPageVO;
import com.jyw.business.obstacles.domain.vo.wechat.WxWorkOrderReviewPageVO;
import com.jyw.business.obstacles.enums.TempEnum;
import com.jyw.business.obstacles.enums.WorkOrderAttributeEnum;
import com.jyw.business.obstacles.mapper.ObsOrderFaultMapper;
import com.jyw.business.obstacles.mapper.ObsOrderProcessMapper;
import com.jyw.business.obstacles.service.*;
import com.jyw.common.constant.SysDictTypeConstant;
import com.jyw.common.core.domain.entity.SysDictData;
import com.jyw.common.core.page.BasePage;
import com.jyw.common.event.AstMeteringCompleteEvent;
import com.jyw.common.excel.ExportUtils;
import com.jyw.common.excel.ObjectParseUtils;
import com.jyw.common.exception.ServiceException;
import com.jyw.common.exception.base.BaseException;
import com.jyw.common.utils.ClassCompareUtil;
import com.jyw.common.utils.DateUtils;
import com.jyw.common.utils.PageUtils;
import com.jyw.common.utils.bean.BeanUtils;
import com.jyw.system.domain.vo.SysOrderReviewConfigAllVo;
import com.jyw.system.mapper.SysDeptMapper;
import com.jyw.system.mapper.SysTeamMapper;
import com.jyw.system.service.ISysDictDataService;
import com.jyw.system.service.ISysOrderReviewConfigService;
import com.jyw.system.utils.ConversionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.jyw.common.utils.SecurityUtils.getUserId;

/**
 * 工单故障Service业务层处理
 *
 * @author system
 * @date 2023-08-10
 */
@Service
@Slf4j
public class ObsOrderFaultServiceImpl extends ServiceImpl<ObsOrderFaultMapper, ObsOrderFault> implements IObsOrderFaultService {

    @Resource
    private ObsOrderFaultMapper obsOrderFaultMapper;

    @Resource
    private IObsOrderInfoService orderInfoService;

    @Resource
    private IObsOrderSendService orderSendService;

    @Resource
    private ISysOrderReviewConfigService orderReviewConfigService;

    @Resource
    private ISysDictDataService sysDictDataService;

    @Resource
    private ObsOrderProcessMapper obsOrderProcessMapper;

    @Resource
    private IObsOrderProcessService processService;

    @Resource
    private IObsOrderMakeService orderMakeService;

    @Resource
    private SysTeamMapper sysTeamMapper;

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private ApplicationContext applicationContext;

    /**
     * 查询工单故障
     *
     * @param id 工单故障主键
     * @return 工单故障
     */
    @Override
    public ObsOrderFault selectObsOrderFaultById(Long id) {
        return obsOrderFaultMapper.selectObsOrderFaultById(id);
    }

    /**
     * 查询工单故障列表
     *
     * @param obsOrderFault 工单故障
     * @return 工单故障
     */
    @Override
    public List<ObsOrderFault> selectObsOrderFaultList(ObsOrderFault obsOrderFault) {
        return obsOrderFaultMapper.selectObsOrderFaultList(obsOrderFault);
    }

    /**
     * 新增工单故障
     *
     * @param obsOrderFault 工单故障
     * @return 结果
     */
    @Override
    public int insertObsOrderFault(ObsOrderFault obsOrderFault) {
        obsOrderFault.setCreateTime(DateUtils.getNowDate());
        return obsOrderFaultMapper.insertObsOrderFault(obsOrderFault);
    }

    /**
     * 修改工单故障
     *
     * @param obsOrderFault 工单故障
     * @return 结果
     */
    @Override
    public int updateObsOrderFault(ObsOrderFault obsOrderFault) {
        obsOrderFault.setUpdateTime(DateUtils.getNowDate());
        return obsOrderFaultMapper.updateObsOrderFault(obsOrderFault);
    }

    /**
     * 批量删除工单故障
     *
     * @param ids 需要删除的工单故障主键
     * @return 结果
     */
    @Override
    public int deleteObsOrderFaultByIds(Long[] ids) {
        return obsOrderFaultMapper.deleteObsOrderFaultByIds(ids);
    }

    /**
     * 删除工单故障信息
     *
     * @param id 工单故障主键
     * @return 结果
     */
    @Override
    public int deleteObsOrderFaultById(Long id) {
        return obsOrderFaultMapper.deleteObsOrderFaultById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ObsOrderInfo add(BaseOrderAddDto addDto) {
        //构建工单信息
        ObsOrderInfo orderInfo = addDto.buildOrder();
        //生成工单号
        orderInfo.setOrderNum(orderInfoService.generateOrderNum());
        //保存工单信息
        orderInfoService.save(orderInfo);
        //创建工单故障
        ObsOrderFault orderFault = addDto.buildOrderFault(orderInfo);
        //记录创建工单流程
        processService.record(OrderProcessRecordDto
                .builder()
                .operState(OrderProcessStateConstant.CREATE_ORDER)
                .orderNum(orderInfo.getOrderNum())
                .processValue(orderFault.getSource().toString()).build());
        //保存故障信息
        save(orderFault);
        //判断是否指定接单人
        if (addDto.canBuildSend()){
            //兼容小程序多选派单部门
            List<ObsOrderSend> sendList = addDto.buildSend();
            //设置工单号
            sendList.forEach(data->data.setOrderNum(orderInfo.getOrderNum()));
            orderSendService.saveBatch(sendList);
            //批量记录派单
            sendList.forEach(send->{
                //创建派单流程
                OrderProcessRecordDto sendProcess = OrderProcessRecordDto
                        .builder()
                        .orderNum(orderInfo.getOrderNum())
                        .operState(OrderProcessStateConstant.ALLOCATE)
                        .build();
                BeanUtils.copyProperties(send, sendProcess);
                processService.record(sendProcess);
            });
            //修改工单为待接单
            lambdaUpdate().eq(ObsOrderFault::getId,orderFault.getId()).set(ObsOrderFault::getCurrState,OrderCurrStateConstant.WAIT_ACCEPT).update();
            log.info("创建工单:{},指定接单人,设置工单状态为待接单", orderInfo.getOrderNum());
            if (addDto.getSendType().equals(1)) {
                //如果是由我处理,需要接单
                orderMakeService.receive(new ReceiveOrderDto() {{
                    setOrderNum(orderInfo.getOrderNum());
                }});
            }
        }
        return orderInfo;
    }

    @Override
    public ObsOrderFault getFaultByOrder(String orderNum) {
        return getOne(new QueryWrapper<ObsOrderFault>().eq(StrUtil.toUnderlineCase(ObsOrderFault.Fields.orderNum), orderNum));
    }

    @Override
    public boolean isAudit(Integer orderSource, String faultType) {
        SysOrderReviewConfigAllVo config = orderReviewConfigService.getConfig();
        //判断是否开启配置
        if (!config.getSysOrderReviewConfig().getIsReview()) {
            return false;
        }
        switch (config.getSysOrderReviewConfig().getReviewMode()) {
            case 1:
                //故障分类,故障来源
                //先检查工单来源
                if (config.getFaultSourceList().stream()
                        .filter(data -> data.getRecordId().equals(orderSource.toString()) && data.getChecked()).findFirst().isPresent()) {
                    return true;
                }
                //检查故障类型
                //查询第一级故障类型
                SysDictData parentFault = sysDictDataService.getTopLevelFaultType(faultType);
                //查询是否开启审核
                if (config.getFaultTypeList().stream().filter(
                        data -> data.getRecordId().equals(parentFault.getDictValue()) && data.getChecked()
                ).findFirst().isPresent()) {
                    return true;
                }
                return false;
            case 2:
                //人员
                return config.getStaffList().stream().filter(data -> Long.valueOf(data.getRecordId()).equals(getUserId())).findFirst().isPresent();
        }
        return false;
    }

    @Override
    public List<ServerPageVO> serverPage(ServerPageDto pageDto, BasePage page) {
        if (!ObjectUtils.isEmpty(page)) {
            PageUtils.startPage();
        }
        List<ServerPageVO> list = obsOrderFaultMapper.serverPage(pageDto);

        return ConversionUtil.conversionList(list, ServerPageVO.class);
    }

    @Override
    public List<ServerCallPageVO> serverCallPage(ServerCallPageDto pageDto, BasePage page) {
        if (!ObjectUtils.isEmpty(page)) {
            PageUtils.startPage();
        }
        List<ServerCallPageVO> list = obsOrderFaultMapper.serverCallPage(pageDto);

        return ConversionUtil.conversionList(list, ServerCallPageVO.class);
    }

    @Override
    public List<WorkOrderPageVO> pageWorkOrder(WorkOrderPageDto workOrderPageDto) {
        return this.baseMapper.pageWorkOrder(workOrderPageDto);
    }

    @Override
    public List<WxWorkOrderReviewPageVO> pageWxProcessWorkOrder(WxWorkOrderReviewPageDto wxWorkOrderReviewPageDto) {
        return this.baseMapper.pageWxProcessWorkOrder(wxWorkOrderReviewPageDto);
    }

    @Override
    public List<WxWorkOrderQueryPageVO> pageWxAllWorkOrder(WxWorkOrderQueryPageDto wxWorkOrderQueryPageDto) {
        if (CollectionUtil.isNotEmpty(wxWorkOrderQueryPageDto.getAttributeList())) {
            Boolean myRepair = false;
            Boolean myHandle = false;
            Boolean others = false;
            for (Integer attr : wxWorkOrderQueryPageDto.getAttributeList()) {
                if (attr.intValue() == WorkOrderAttributeEnum.MY_REPAIR.getValue()) {
                    myRepair = true;
                }
                if (attr.intValue() == WorkOrderAttributeEnum.MY_HANDLE.getValue()) {
                    myHandle = true;
                }
                if (attr.intValue() == WorkOrderAttributeEnum.OTHERS.getValue()) {
                    others = true;
                }
            }
            //排除全部选择
            if(!(myRepair&&myHandle&&others)){
                Integer attributeType=0;
                if(myRepair&&!myHandle&&!others){
                    attributeType=1;
                }
                if(!myRepair&&myHandle&&!others){
                    attributeType=2;
                }
                if(!myRepair&&!myHandle&&others){
                    attributeType=3;
                }
                if(myRepair&&myHandle&&!others){
                    attributeType=4;
                }
                if(myRepair&&!myHandle&&others){
                    attributeType=5;
                }
                if(!myRepair&&myHandle&&others){
                    attributeType=6;
                }
                wxWorkOrderQueryPageDto.setAttributeType(attributeType);
            }
        }
        return this.baseMapper.pageWxAllWorkOrder(wxWorkOrderQueryPageDto);
    }

    @Override
    public List<ProcessedPageVO> pageProcessed(WorkOrderPageDto workOrderPageDto) {
        workOrderPageDto.setUserId(getUserId());
        return this.baseMapper.pageProcessed(workOrderPageDto);
    }

    @Override
    @Transactional(rollbackFor = BaseException.class)
    public void enact(String orderNums) {
        try {
            String orderArray[] = orderNums.split(",");
            if (orderArray == null || orderArray.length == 0) {
                throw new BaseException("提交工单号错误");
            }
            for (String orderNum : orderArray) {
                QueryWrapper<ObsOrderFault> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("order_num", orderNum);
                ObsOrderFault obsOrderFault = this.getOne(queryWrapper);
                if (obsOrderFault == null) {
                    throw new BaseException("未找到工单");
                }
                if (!obsOrderFault.getCurrState().equals(OrderCurrStateConstant.WAIT_AUDIT)) {
                    throw new BaseException("工单不能审核,状态已改！");
                }
                //转交操作流程
                ObsOrderProcess obsOrderProcess = new ObsOrderProcess();
                //工单号
                obsOrderProcess.setOrderNum(orderNum);
                //上次工单状态（待审核）
                obsOrderProcess.setLastFaultState(OrderCurrStateConstant.WAIT_AUDIT);
                //操作类型（审核）
                obsOrderProcess.setOperState(OrderProcessStateConstant.EXAMINE);
                //审核通过
                obsOrderProcess.setProcessValue(OrderExamineStateConstant.END_EXAMINE);
                obsOrderProcess.setCreateTime(new Date());
                obsOrderProcess.setCreateUser(getUserId());
                obsOrderProcessMapper.insert(obsOrderProcess);
                //修改主表状态
                obsOrderFault.setCurrState(OrderCurrStateConstant.WAIT_APPRAISAL);
                obsOrderFault.setUpdateTime(new Date());
                obsOrderFault.setUpdateUser(getUserId());
                this.updateById(obsOrderFault);


                //判断工单来源如果是工单保养,那么进入待评价时,保养续期
                if(obsOrderFault.getSource().equals(OrderSourceConstant.AST_METERING)){
                    log.info("资产保养完成,发送保养完成事件,资产Id:{}",obsOrderFault.getAssetsId());
                    //保养续期
                    applicationContext.publishEvent(new AstMeteringCompleteEvent(obsOrderFault.getAssetsId()));
                }
            }
        } catch (BaseException e) {
            throw new BaseException("工单通过失败");
        } catch (Exception e) {
            throw new BaseException("工单通过失败");
        }
    }

    @Override
    @Transactional(rollbackFor = BaseException.class)
    public void reject(OrderRejectUpdDto dto) {
        try {
            QueryWrapper<ObsOrderFault> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_num", dto.getOrderNum());
            ObsOrderFault obsOrderFault = this.getOne(queryWrapper);
            if (obsOrderFault == null) {
                throw new BaseException("未找到工单");
            }
            if (!obsOrderFault.getCurrState().equals(OrderCurrStateConstant.WAIT_AUDIT)) {
                throw new BaseException("工单不能审核,状态已改！");
            }
            //转交操作流程
            ObsOrderProcess obsOrderProcess = new ObsOrderProcess();
            //工单号
            obsOrderProcess.setOrderNum(dto.getOrderNum());
            //上次工单状态（待审核）
            obsOrderProcess.setLastFaultState(OrderCurrStateConstant.WAIT_AUDIT);
            //操作类型（审核）
            obsOrderProcess.setOperState(OrderProcessStateConstant.EXAMINE);
            //审核通过
            obsOrderProcess.setProcessValue(OrderExamineStateConstant.NO_EXAMINE);
            obsOrderProcess.setCreateTime(new Date());
            obsOrderProcess.setCreateUser(getUserId());
            obsOrderProcessMapper.insert(obsOrderProcess);
            //修改主表状态
            obsOrderFault.setCurrState(OrderCurrStateConstant.NOT_PASS_AUDIT);
            obsOrderFault.setUpdateTime(new Date());
            obsOrderFault.setUpdateUser(getUserId());
            this.updateById(obsOrderFault);
        } catch (BaseException e) {
            throw new BaseException("工单驳回失败");
        }
    }

    @Override
    public List<OrderAllPageVO> pageWholeOrder(OrderAllPageDto dto) {
        List<OrderAllPageVO> list=this.baseMapper.pageWholeOrder(dto);
        return ConversionUtil.conversionList(list,OrderAllPageVO.class);
    }

    @Override
    public void exportProduct(HttpServletResponse response, OrderAllPageDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "工单" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderAllPageVO> orderLists = this.baseMapper.pageWholeOrder(dto);
        for (OrderAllPageVO vo : orderLists) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            String listStr = gs.toJson(vo);
            OrderAllPageExcelVO excelVO = gs.fromJson(listStr, OrderAllPageExcelVO.class);
            //TODO 等待状态全部完成再修改
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        try {
            ExportUtils.exportExport(listMap, "excelTemplate/obs_order.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(OrderEditDto editDto) {
        //获取工单
        ObsOrderInfo one = orderInfoService.lambdaQuery().eq(ObsOrderInfo::getOrderNum, editDto.getOrderNum()).one();
        if (ObjectUtils.isEmpty(one)) {
            throw new ServiceException("工单不存在");
        }
        //比对
        ObsOrderInfo newInfo = editDto.buildOrder(one);

        Map<String, Map<String, Object>> compareMap = ClassCompareUtil.compareFields(one, newInfo);
        //修改数据
        orderInfoService.updateById(newInfo);
        //获取故障
        ObsOrderFault oldFault = lambdaQuery().eq(ObsOrderFault::getOrderNum, editDto.getOrderNum()).one();
        if (ObjectUtils.isEmpty(oldFault)) {
            throw new ServiceException("故障不存在");
        }
        //比对
        ObsOrderFault newFault = editDto.buildOrderFault(oldFault);
        compareMap.putAll(ClassCompareUtil.compareFields(oldFault, newFault));
        //修改数据
        updateById(newFault);
        //记录流程
        OrderProcessRecordDto processRecordDto = OrderProcessRecordDto
                .builder()
                .orderNum(editDto.getOrderNum())
                .operState(OrderProcessStateConstant.EDIT_ORDER)
                .processValue(JSONObject.toJSONString(compareMap))
                .build();
        processService.record(processRecordDto);
    }

    @Override
    public List<OrderStatisticsVO> statisticsSource(ObsStatisticsBaseQueryDto dto) {
        dto.setDictType(SysDictTypeConstant.OBS_FAULT_SOURCE);
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsSource(dto);
        return statisticsVOList;
    }

    @Override
    public List<OrderFaultTypeStatisticsVO> statisticsFaultType(ObsStatisticsBaseQueryDto dto) {
        dto.setDictType(SysDictTypeConstant.OBS_FAULT_TYPE);
        List<OrderFaultTypeStatisticsVO> statisticsVOList = this.baseMapper.statisticsFaultType(dto);
        for (OrderFaultTypeStatisticsVO vo : statisticsVOList) {
            String dictValueByParentId = this.baseMapper.getDictValueByParentId(vo.getId());
            if (dictValueByParentId != null) {
                Integer childTotal = this.baseMapper.getChildTotal(dictValueByParentId);
                vo.setChildTotal(childTotal);
            }
        }
        return statisticsVOList;
    }

    @Override
    public List<OrderStatisticsVO> statisticsDeptRepair(ObsStatisticsBaseQueryDto dto) {
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsDeptRepair(dto);
        return statisticsVOList;
    }

    @Override
    public List<OrderStatisticsVO> statisticsEngineer(ObsStatisticsBaseQueryDto dto) {
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsEngineer(dto);
        return statisticsVOList;
    }

    @Override
    public List<CommonFaultsCountVO> statisticsCommonFault(ObsStatisticsBaseQueryDto dto) {
        // 获取所有部门子类
        dto.setDeptIds(sysDeptMapper.getDeptChildList(dto.getDeptId()));
        List<CommonFaultsCountVO> statisticsVOList = this.baseMapper.statisticsCommonFault(dto);
        Map<String, List<CommonFaultsCountVO>> classMap = statisticsVOList.stream().collect(Collectors.groupingBy(CommonFaultsCountVO::getDictLabel));
        List<CommonFaultsCountVO> list = new ArrayList<>();
        classMap.forEach((key, value) -> {
            CommonFaultsCountVO countVO = new CommonFaultsCountVO();
            countVO.setDictLabel(key);
            List<CommonFaultsCountVO> listCount = classMap.get(key);
            int num = listCount.stream().mapToInt(CommonFaultsCountVO::getNum).sum();
            countVO.setNum(num);
            countVO.setChild(listCount);
            list.add(countVO);
        });
        return list;
    }

    @Override
    public List<ServiceDeskStatisticsVO> statisticsWork(ObsStatisticsBaseQueryDto dto) {
        // 获取所有部门子类
        dto.setDeptIds(sysDeptMapper.getDeptChildList(dto.getDeptId()));
        List<ServiceDeskStatisticsVO> statisticsVOList = this.baseMapper.statisticsWork(dto);


        return statisticsVOList;
    }

    @Override
    public void exportSource(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "故障来源" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsSource(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "故障来源");
        } else {
            map.put("title", "故障来源");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_source.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportFaultType(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "故障分类" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderFaultTypeStatisticsVO> list = this.statisticsFaultType(dto);
        int total = list.stream().mapToInt(OrderFaultTypeStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderFaultTypeStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "故障分类");
        } else {
            map.put("title", "故障分类");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_fault_type.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportDeptRepair(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "科室报修情况(工单数量)" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsDeptRepair(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "科室报修情况(工单数量)");
        } else {
            map.put("title", "科室报修情况(工单数量)");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_dept_repair.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportEngineer(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "工程师排名(工单数量)" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsEngineer(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "工程师排名(工单数量)");
        } else {
            map.put("title", "工程师排名(工单数量)");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_engineer.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public ServerCountVO serverCount(ServerTotalDto totalDto) {
        ServerCountVO result = new ServerCountVO();
        totalDto.setTemp(TempEnum.MANUAL_CREATE);
        result.setManualCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WECHAT_CREATE);
        result.setWechatCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PHONE_CREATE);
        result.setPhoneCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PICKED_UP);
        result.setPickedUp(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.MISSED);
        result.setMissed(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_DELIVERY);
        result.setWaitDelivery(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.UNTENITED);
        result.setUntenited(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.FIND_SOMEONE);
        result.setFindSomeone(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.END_PHONE);
        result.setEndPhone(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_ACCEPT);
        result.setWaitAccept(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PROCESSING);
        result.setProcessing(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_AUDIT);
        result.setWaitAudit(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.TRANSFORM);
        result.setTransform(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.TERMINATED);
        result.setTerminated(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.SUSPENDED);
        result.setSuspended(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_APPRAISAL);
        result.setWaitAppraisal(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.NOT_PASS_AUDIT);
        result.setNotPassAudit(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.ENDED);
        result.setEnded(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.CREATE_ORDER);
        result.setCreateOrder(obsOrderFaultMapper.serverCount(totalDto));
        return result;
    }

    @Override
    public OrderPrintVO getPrintOrderInfo(Long id) {
        //通过id获取信息
        ObsOrderInfo info = orderInfoService.getById(id);
        if (ObjectUtils.isEmpty(info)) {
            return null;
        }
        //通过工单号获取详情
        OrderDetailVO detail = orderInfoService.detail(info.getOrderNum());

        return detail.buildPrint();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocate(AllocateDto dto) {
        ObsOrderFault fault = getFaultByOrder(dto.getOrderNum());
        if(ObjectUtils.isEmpty(fault)){
            throw new ServiceException("工单不存在");
        }
        if(!Lists.newArrayList(OrderCurrStateConstant.WAIT_DELIVERY,OrderCurrStateConstant.WAIT_ACCEPT).contains(fault.getCurrState())){
            throw new ServiceException("当前不能派单");
        }
        //查询是否存在派单记录
            //已经派过单了,删除原来的派单记录
        orderSendService.lambdaUpdate().eq(ObsOrderSend::getOrderNum,dto.getOrderNum()).remove();
        //新增派单记录
        ObsOrderSend send = dto.buildSend();
        orderSendService.save(send);
        //修改故障状态为待派单
        lambdaUpdate().eq(ObsOrderFault::getOrderNum,dto.getOrderNum())
                .set(ObsOrderFault::getCurrState,OrderCurrStateConstant.WAIT_ACCEPT).update();
        //创建派单流程
        OrderProcessRecordDto sendProcess = OrderProcessRecordDto
                .builder()
                .lastFaultState(fault.getCurrState())
                .orderNum(dto.getOrderNum())
                .operState(OrderProcessStateConstant.ALLOCATE)
                .build();
        BeanUtils.copyProperties(send, sendProcess);
        processService.record(sendProcess);
    }

    @Override
    public List<WorkOrderQueryVO> listWeChatOrder(WorkOrderQueryDto dto) {
        //小组
        List<Long> teamList = new ArrayList<Long>();
        //用户
        List<Long> userList = new ArrayList<Long>();
        //查询自己的
        userList.add(getUserId());
        //查询自己对应的组的
        if (userList.size() > 0) {
            for (Long userId : userList) {
                List<Long> teamsList = sysTeamMapper.getTeamList(userId);
                for (Long teamId : teamsList) {
                    if (!teamList.contains(teamId)) {
                        teamList.add(teamId);
                    }
                }
            }
        }
        dto.setUserList(userList);
        dto.setTeamList(teamList);
        List<WorkOrderQueryVO> listWeChatOrder = this.baseMapper.listWeChatOrder(dto);
        return listWeChatOrder;
    }

    @Override
    public List<LinkOrderVO> linkOrder(String phone) {
        List<LinkOrderVO> list = obsOrderFaultMapper.linkOrder(phone);
        list.forEach(data->data.processMakeUser());
        return ConversionUtil.conversionList(list,LinkOrderVO.class);
    }

}
